using System;
using System.Collections.Generic;
using System.Text;
using Rules;
using Client;
namespace Server
{
    public enum PokerGameStatus : int
    {
        WaitForStart,
        Begin,
        Flop,
        Turn,
        River
    };
    class PokerGame//:  IPokerGame
    {
        private static PokerRules Arbiter;

        private List<Card> Deck = new List<Card>();

        
        private System.Collections.Generic.Dictionary<int,PokerPlayer> Players=new System.Collections.Generic.Dictionary<int,PokerPlayer>();
        private int? dealer_id;
        private PokerRoomOptions rules;
        private List<Card> Table = new List<Card>();
        //private int on_table;
        private int actual_max_bet;
        private Action lastMove=new Action();
        private PokerGameStatus Status;

        public int next_player_id(int ID)
        {

           
            List<int> temp=new List<int>();
            foreach (PokerPlayer player in Players.Values)
                 temp.Add(player.Chair_number);
            temp.Sort();
            int nr=temp.BinarySearch(Players[ID].Chair_number);

            if (nr == temp.Count - 1) nr = temp[0];
            else nr=temp[nr+1];

            int next_id = ID;
            foreach (PokerPlayer player in Players.Values)
            {
                if (player.Chair_number == nr) next_id = player.ID;
            }

            return next_id;

        }

        private void SchufleDeck()
        {
        }

        private Card GetCardFromDeck()
        {
            
            Card temp = Deck[0];
            Deck.RemoveAt(0);
            Deck.Insert(Deck.Count, temp);
            return temp;
        }

        public void RiseBlind()
        {
            rules.Blind *= rules.BlindMultiplicity;
        }

        /// <summary>
        /// Ends current round
        /// </summary>
        /// <returns>Next round type</returns>
        public void EndRound()
        {
            if (Status == PokerGameStatus.River)
            {
                //todo ALL IN
                List<PokerPlayer> winners = new List<PokerPlayer>();
                int max_points = 0;
                int gold = 0;
                foreach (PokerPlayer player in Players.Values)
                {
                    gold += player.ActualBet; 
                    player.Money -= player.ActualBet;
                    
                    if (player.Status == ActionList.Bet)
                    {
                        int player_points = Arbiter.CombinationPoints(Arbiter.BestCombiantion(Table, player));
                        if (player_points == max_points) winners.Add(player);
                        if (player_points > max_points) { max_points = player_points; winners.Clear(); winners.Add(player); }
                    }

                    player.Status = ActionList.Lost;
                }

                foreach (PokerPlayer player in winners)
                {
                    player.Money = gold / winners.Count;
                    player.Status = ActionList.Win;
                }
                dealer_id = next_player_id((int)dealer_id);       
            }

            if (Status == PokerGameStatus.Turn)
            {
                Table.Add(GetCardFromDeck());
            }
            if (Status == PokerGameStatus.Flop) Table.Add(GetCardFromDeck()); 
            if (Status == PokerGameStatus.Begin)
            {
                Table.Add(GetCardFromDeck());
                Table.Add(GetCardFromDeck());
                Table.Add(GetCardFromDeck());
            }
        }

        public void Begin()
        {
            Table.Clear();
            SchufleDeck();
           
            foreach (PokerPlayer player in Players.Values)
            {
                if (player.Status != ActionList.LeaveGame)
                {
                    player.Card1 = GetCardFromDeck();
                    player.Card2 = GetCardFromDeck();
                }
            }
            int next = next_player_id((int)dealer_id);
            if (!Bet(rules.Blind, Players[next].ID))
                Bet(Players[next].Money, Players[next].ID);

            next = next_player_id(next);
            if (!Bet(2 * rules.Blind, Players[next].ID))
                Bet(Players[next].Money, Players[next].ID);
            Status = PokerGameStatus.Begin;
        }

        public PokerGame(PokerRoomOptions r) 
        { 
            
            if (Arbiter == null) Arbiter = new PokerRules(); 
            
            actual_max_bet=0;
            rules=r;
            Status = PokerGameStatus.WaitForStart;

            for (CardFace i = CardFace.two; i < CardFace.Ace; i++)
                for (CardColor j = CardColor.Clubs; j < CardColor.Spades; j++)
                    Deck.Add(new Card(i, j));
            
        }

        public bool Bet(int BetSize, int ID)
        {
            
            //you can't rise your self
            if( actual_max_bet== Players[ID].ActualBet ) return false;
            
            if( actual_max_bet > Players[ID].ActualBet+BetSize) return false;

            if( (actual_max_bet - Players[ID].ActualBet +BetSize )>rules.MaximumBetMultiplicity*rules.Blind*2 ) return false;

            if( Players[ID].Money<Players[ID].ActualBet+BetSize) return false;
            
            Players[ID].ActualBet+=BetSize;
            actual_max_bet=Players[ID].ActualBet;
            lastMove.ActionType=ActionList.Bet;
            lastMove.PlayerID=ID;
            lastMove.Money=BetSize;
            return true;
            
        }

        PokerTable GetTable(int ID)
        {
            PokerTable return_table = new PokerTable();
            return_table.CardsOnTable.AddRange(Table);
            foreach(PokerPlayer player in Players.Values)
            {
                if(player.ID!=ID)
                return_table.Players.Add(new PokerPlayer(player, true));
                else return_table.Players.Add(new PokerPlayer(player, false));
            }
            return return_table;
        }

        bool Pass(int ID)
        {
            Players[ID].Status = ActionList.Pass;
            return true;
        }

        bool EndGame(int ID)
        {
            Players[ID].Status = ActionList.LeaveGame;
            return true;
            
        }

        Action LastMove(int ID)
        {
            return lastMove;
        }

        bool Join(PokerPlayer player)
        {
            if (Players.Count < rules.MaximumPlayers - 1)
            {
                if (!dealer_id.HasValue) dealer_id = player.ID;
                Players.Add(player.ID, player);
                return true;
            }
            else return false;
        }
    }
}
